----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    10:39:18 09/18/2013 
-- Design Name: 
-- Module Name:    alu - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity alu is
Port (	Clk		: in	STD_LOGIC;
			Control	: in	STD_LOGIC_VECTOR (5 downto 0);
			Operand1	: in	STD_LOGIC_VECTOR (31 downto 0);
			Operand2	: in	STD_LOGIC_VECTOR (31 downto 0);
			Result1	: out	STD_LOGIC_VECTOR (31 downto 0);
			Result2	: out	STD_LOGIC_VECTOR (31 downto 0);
			Debug		: out	STD_LOGIC_VECTOR (31 downto 0));
end alu;

architecture Behavioral of alu is
	-- command control mapping
	constant NOP_INSTR 	: std_logic_vector 	:= "00" & X"0"; 
	constant ADD_INSTR 	: std_logic_vector 	:= "00" & X"1"; 
	constant ADDU_INSTR 	: std_logic_vector 	:= "00" & X"2"; 
	constant SUB_INSTR 	: std_logic_vector 	:= "00" & X"3"; 
	constant SUBU_INSTR 	: std_logic_vector 	:= "00" & X"4"; 
	constant MULT_INSTR 	: std_logic_vector 	:= "00" & X"5"; 
	constant MULTU_INSTR : std_logic_vector 	:= "00" & X"6"; 
	constant DIV_INSTR 	: std_logic_vector 	:= "00" & X"7"; 
	constant DIVU_INSTR 	: std_logic_vector 	:= "00" & X"8"; 
	constant XOR_INSTR 	: std_logic_vector 	:= "00" & X"9"; 
	constant AND_INSTR 	: std_logic_vector 	:= "00" & X"A"; 
	constant OR_INSTR 	: std_logic_vector 	:= "00" & X"B"; 
	constant NOR_INSTR 	: std_logic_vector 	:= "00" & X"C"; 
	constant SRA_INSTR 	: std_logic_vector 	:= "00" & X"D"; 
	constant SRL_INSTR 	: std_logic_vector 	:= "00" & X"E"; 
	constant SLL_INSTR 	: std_logic_vector 	:= "00" & X"F"; 
	constant SLT_INSTR 	: std_logic_vector 	:= "01" & X"0"; 
	constant BEQ_INSTR 	: std_logic_vector 	:= "01" &X"1"; 
	constant BNE_INSTR 	: std_logic_vector 	:= "01" &X"2"; 
	
	-- flag mapping for bits in Debug signal
	constant BEQ_BIT 			: integer := 0;	-- is set to '1' if instruction: (BEQ A, B) and (A = B) else '0'
	constant BNE_BIT 			: integer := 1;	-- is set to '1' if instruction: (BNE A, B) and (A != B) else '0'
	constant SLT_BIT 			: integer := 2; 	-- is set to '1' if instruction: (SLT A, B) and (A < B) else '0'	
	constant OVERFLOW_BIT 	: integer := 3;	-- is set to '1' if there is an overflow during addition or subtraction
	
	component add_sub_32 is
		 Port ( subControl : in STD_LOGIC;
				  a : in  STD_LOGIC_VECTOR (31 downto 0);
				  b : in  STD_LOGIC_VECTOR (31 downto 0);
				  result : out  STD_LOGIC_VECTOR (31 downto 0);
				  carryOut : out  STD_LOGIC);
	end component;
	
	component xor_and_or_32 is
		 Port ( a : in  STD_LOGIC_VECTOR (31 downto 0);
				  b : in  STD_LOGIC_VECTOR (31 downto 0);
				  xorOutput : out  STD_LOGIC_VECTOR (31 downto 0);
				  andOutput : out  STD_LOGIC_VECTOR (31 downto 0);
				  orOutput : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	component left_shifter is
		 Port (	clk : in STD_LOGIC;
					input : in  STD_LOGIC_VECTOR (31 downto 0);
					shiftValue : in STD_LOGIC_VECTOR (4 downto 0);
					output : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	component right_shifter is
		 Port (	clk : in STD_LOGIC;
					input : in  STD_LOGIC_VECTOR (31 downto 0);
					arthControl : in STD_LOGIC;
					shiftValue : in STD_LOGIC_VECTOR (4 downto 0);
					output : out  STD_LOGIC_VECTOR (31 downto 0));
	end component;
	
	component comparator_32 is		
		 Port ( op1 : in  STD_LOGIC_VECTOR (31 downto 0);
				  op2 : in  STD_LOGIC_VECTOR (31 downto 0);
				  op1IsLess, isEqual : out STD_LOGIC);
	end component;
	
	component mult_div is
		port(	signControl, divControl, clock : in STD_LOGIC;
				a, b : in STD_LOGIC_VECTOR(31 downto 0);
				result : out STD_LOGIC_VECTOR(63 downto 0));
	end component;
	
	signal subControl : STD_LOGIC := '0';
	signal signControl : STD_LOGIC := '0';
	signal divControl : STD_LOGIC := '0';
	
	signal addSubOutput : STD_LOGIC_VECTOR(31 downto 0);
	signal carryOut31 : STD_LOGIC;
	signal multDivOutput1 : STD_LOGIC_VECTOR(63 downto 0);
	
	signal xorOutput : STD_LOGIC_VECTOR(31 downto 0);
	signal andOutput : STD_LOGIC_VECTOR(31 downto 0);
	signal orOutput : STD_LOGIC_VECTOR(31 downto 0);
	
	signal rightShifterArthControl : STD_LOGIC := '0';
	signal rightShifterOutput : STD_LOGIC_VECTOR(31 downto 0);
	signal leftShifterOutput : STD_LOGIC_VECTOR(31 downto 0);
	
	signal op1IsLess : STD_LOGIC := '0';
	signal isEqual : STD_LOGIC := '0';
	
begin
	addSub1 : add_sub_32 port map(subControl, Operand1, Operand2, addSubOutput, carryOut31);
	xorAndOr1 : xor_and_or_32 port map(Operand1, Operand2, xorOutput, andOutput, orOutput);
	rightShifter1 : right_shifter port map(Clk, Operand1, rightShifterArthControl, Operand2(4 downto 0), rightShifterOutput);
	leftShifter1 : left_shifter port map(Clk, Operand1, Operand2(4 downto 0), leftShifterOutput);
	comparator1 : comparator_32 port map(Operand1, Operand2, op1IsLess, isEqual);
	multDiv1 : mult_div port map(signControl, divControl, Clk, Operand1, Operand2, multDivOutput1);
process (Clk)
begin  
   if (Clk'event and Clk = '1') then
	-- reset instruction
      if Control(5) = '1' then
         Result1 <= X"00000000";
			Result2 <= X"00000000";
			Debug <= X"00000000";
			
		-- all other instructions
      else
			if Control = NOP_INSTR then
				-- do nothing
				
			elsif Control = ADD_INSTR then
				subControl <= '0';
				Result1 <= addSubOutput;
				Debug(OVERFLOW_BIT) <= carryOut31;
				
			elsif Control = ADDU_INSTR then
				subControl <= '0';
				Result1 <= addSubOutput;
				
			elsif Control = SUB_INSTR then
				subControl <= '1';
				Result1 <= addSubOutput;
				Debug(OVERFLOW_BIT) <= carryOut31;
				
			elsif Control = SUBU_INSTR then
				subControl <= '1';
				Result1 <= addSubOutput;
				
			elsif Control = MULT_INSTR then
				signControl <= '1';
				divControl <= '0';
				Result2 <= multDivOutput1(63 downto 32);
				Result1 <= multDivOutput1(31 downto 0);
				
			elsif Control = MULTU_INSTR then
				signControl <= '0';
				divControl <= '0';
				Result2 <= multDivOutput1(63 downto 32);
				Result1 <= multDivOutput1(31 downto 0);
				
			elsif Control = DIV_INSTR then
				signControl <= '1';
				divControl <= '1';
				Result2 <= multDivOutput1(63 downto 32);
				Result1 <= multDivOutput1(31 downto 0);
				
			elsif Control = DIVU_INSTR then
				signControl <= '1';
				divControl <= '1';
				Result2 <= multDivOutput1(63 downto 32);
				Result1 <= multDivOutput1(31 downto 0);
				
			elsif Control = XOR_INSTR then
				Result1 <= xorOutput;
				
			elsif Control = AND_INSTR then
				Result1 <= andOutput;
				
			elsif Control = OR_INSTR then
				Result1 <= orOutput;
				
			elsif Control = NOR_INSTR then
				Result1 <= NOT(orOutput);
					
			elsif Control = SRA_INSTR then
				rightShifterArthControl <= '1';
				Result1 <= rightShifterOutput;
				
			elsif Control = SRL_INSTR then
				rightShifterArthControl <= '0';
				Result1 <= rightShifterOutput;
			
			elsif Control = SLL_INSTR then
				Result1 <= leftShifterOutput;
				
			elsif Control = SLT_INSTR then
				Debug(SLT_BIT) <= op1IsLess;
				
			elsif Control = BEQ_INSTR then
				Debug(BEQ_BIT) <= isEqual;
				
			elsif Control = BNE_INSTR then
				Debug(BNE_BIT) <= NOT(isEqual);
				
			else
				-- do nothing
			end if;
      end if;
	end if;
end process;
end Behavioral;

